#include <iostream>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;

#define NUM 1024

void Usage(string proc)
{
    cout << "Usage \r\t" << proc << " server_port" << endl;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }

    int16_t port = atoi(argv[1]);

    // 1.创建套接字
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        cerr << "socket error" << errno << endl;
        return 2;
    }

    // 2.绑定端口号和IP(特殊处理)
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(port); // 端口号是计算机上的变量，为主机序列，需要变为网络序列————htonel()函数
    /*
     * a. IP地址常用点分十进制表示，也需要转换为4字节的整数
     * b. 也要考虑大小端和主机/网络序列问题
     */
    // 坑：云服务器不允许用户直接bind公网IP，同时在实际编写时也不会bind公网IP
    // local.sin_addr.s_addr = inet_addr("101.43.172.203");

    // INADDR_ANY:如果使用确切的IP，那么只会接收到该IP下主机获得数据，而服务器通常有多个网卡，配置多个IP
    // 我们需要的不是某个IP上的数据，而是发送到该主机上端口的数据
    // /#define INADDR_ANY ((in_addr_t) 0x00000000)
    local.sin_addr.s_addr = INADDR_ANY;
    if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0)
    {
        cerr << "bind error" << errno << endl;
        return 3;
    }

    // 3.提供服务
    bool quit = false;
    char buffer[NUM]; // 缓冲区————接收客服端发送的数据
    while (!quit)
    {

        // peer 保存客户端的sockaddr，用于反馈数据时能找到客户端的IP和PORT
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        ssize_t ret = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
        if (ret > 0)
        {
            // 在有效字符后加'\0' 表示为字符串
            buffer[ret] = 0;
            cout << "client# " << buffer << endl;

            // 接收到数据，反馈给客户端字符串 = buffer...
            string message = {buffer};
            message += "...";
            sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr *)&peer, len);
        }
        else
        {
            // TODO
        }
    }
    return 0;
}
